package com.xiaoyu.shenyou.shenyouv1.services.impl;

import cn.hutool.core.util.ObjectUtil;
import com.xiaoyu.shenyou.shenyouv1.common.roomname.RoomName;
import com.xiaoyu.shenyou.shenyouv1.entity.PredNameEntity;
import com.xiaoyu.shenyou.shenyouv1.entity.RelationEntity;
import com.xiaoyu.shenyou.shenyouv1.mapper.PredictionMapper;
import com.xiaoyu.shenyou.shenyouv1.mapper.RecordMapper;
import com.xiaoyu.shenyou.shenyouv1.entity.PredictionEntity;
import com.xiaoyu.shenyou.shenyouv1.entity.RecordEntity;
import com.xiaoyu.shenyou.shenyouv1.services.PredictionService;
import com.xiaoyu.shenyou.shenyouv1.vo.PredictionVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PredictionServiceImpl implements PredictionService {

    @Autowired
    private PredictionMapper predictionMapper;

    @Autowired
    private RecordMapper recordMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    /**
     * 插入预测
     *
     * @param killRoom
     */
    @Override
    @Async
    public void insertPrediction(String killRoom, int games) {
        Optional.ofNullable(predictionMapper.queryPredNames()).ifPresent(PredNameEntities -> {
            PredNameEntities.stream()
                    .distinct()
                    .map(name -> name.getName())
                    .forEach(predName -> {
                        PredictionEntity prediction = Optional.ofNullable(predictionMapper.selectLastMethods(predName))
                                .orElseGet(() -> new PredictionEntity()
                                        .setPrediction_room("数据初始化")
                                        .setName(predName)
                                        .setGames(0).setSuccess_count(0)
                                        .setCreate_time(LocalDateTime.now())
                                        .setContinue_fail(0)
                                        .setKill_room("数据初始化"));
                        //取出最后一条记录更改
                        prediction.setKill_room(killRoom);
                        if (!killRoom.equals(prediction.getPrediction_room())) {
                            //不相同则连胜加一
                            prediction.setSuccess_count(prediction.getSuccess_count() + 1);
                            prediction.setContinue_fail(0);
                        } else {
                            //预测失败
                            prediction.setSuccess_count(0);
                            prediction.setContinue_fail(prediction.getContinue_fail() + 1);
                        }
                        //更该预测
                        predictionMapper.updateLastMethod(prediction);
                        //插入一条预测
                        PredictionEntity newPredict = new PredictionEntity();
                        newPredict.setName(predName)
                                .setGames(games + 1)
                                .setCreate_time(LocalDateTime.now())
                                .setSuccess_count(prediction.getSuccess_count())
                                .setKill_room("???")
                                .setContinue_fail(prediction.getContinue_fail());
                        processPrediction(newPredict, predName);
                        predictionMapper.insertPrediction(newPredict);
                        //查出对应算法计算胜率，取出100条对应的算法
                        Optional.ofNullable(predictionMapper.queryPredsByPredName(predName, 100)).ifPresent(predictions -> {
                            double successPercent = this.calculatePercent(predictions);
                            //更新对应的算法胜率
                            predictionMapper.UpdatePredicName(predName, successPercent);
                            //加入到缓存当中
                            redisTemplate.opsForValue().set(predName, predictions);
                            redisTemplate.expire(predName, 5, TimeUnit.MINUTES);
                        });
                    });

        });

    }

    /**
     * 根据id查询对应得算法
     * 查询对应得算法
     *
     * @param userId
     * @return
     */
    @Override
    public List<PredictionEntity> selectPredic(int userId, String name) {
        //查询出预测算法
        List<PredictionEntity> predictionEntities = null;
        try {
            predictionEntities = (List<PredictionEntity>) redisTemplate.opsForValue().get(name);
        } catch (Exception e) {
            log.error("类型转换异常，{}", e.getMessage());
        }
        if (predictionEntities == null || predictionEntities.size() == 0) {
            predictionEntities = predictionMapper.queryPredsByPredName(name, 100);
        }
        //根据id查询出codes
        //匹配查询出的算法code是否符合
        List<Integer> codes = predictionMapper.queryRelations(userId).stream()
                .map(relation -> relation.getCode())
                .collect(Collectors.toList());
        codes.add(1001);
        //根据codes查询preNames
        List<PredNameEntity> predNameEntities = predictionMapper.queryPredNamesByList(codes);
        if (predNameEntities.size() != 0) {
            //是否有匹配
            boolean match = predNameEntities.stream()
                    .map(predNameEntity -> predNameEntity.getName())
                    .distinct()
                    .anyMatch(queryName -> queryName.equals(name));
            if (match) {
                return predictionEntities;
            }
        }
        //判断name是否在names中
        return null;
    }

    @Override
    public double calculatePercent(List<PredictionEntity> predictionEntities) {
        //计算胜率
        try {
            double size = predictionEntities.size();
            int failCount = (int) predictionEntities.stream().filter(predictionEntity -> predictionEntity.getPrediction_room().equals(predictionEntity.getKill_room())).count();
            return Math.round((size - failCount) / size * 100);
        } catch (Exception e) {
            log.error("胜率计算异常，{}", e.getMessage());
            return 0;
        }
    }

    /**
     * 根据id，查询算法名字集合
     *
     * @param userId
     * @return
     */
    @Override
    public List<PredNameEntity> selectPredicName(int userId) {
        //查出有权限的
        //根据id查询出code
        List<RelationEntity> relations = predictionMapper.queryRelations(userId);
        List<Integer> collect = relations.stream()
                .map(relation -> relation.getCode())
                .distinct()
                .collect(Collectors.toList());
        collect.add(1001);
        List<PredNameEntity> sortPreNames = predictionMapper.queryPredNamesByList(collect).stream()
                .distinct()
                .sorted(((o1, o2) -> (int) (o2.getPercentage() - o1.getPercentage())))
                .collect(Collectors.toList());
        return sortPreNames;
    }

    /**
     * 扩展处理
     *
     * @param newPredict
     * @param predName
     */
    private void processPrediction(PredictionEntity newPredict, String predName) {

        if (predName.equals("统计算法三连法") || predName.equals("统计算法二连法") || predName.equals("统计算法一连法")) {
            newPredict.setPrediction_room("等待中");
            return;
        }
        //插入追龙算法
        if (predName.equals("追龙预测法")) {
            //找出最大的值，进行预测
            //查询出记录中的最后一条
            RecordEntity recordLast = recordMapper.selectRecordLast();
            HashMap<Integer, String> successCountRoom = new HashMap<>();
            successCountRoom.put(recordLast.getHuoyan_win(), RoomName.huoyan);
            successCountRoom.put(recordLast.getNver_win(), RoomName.nver);
            successCountRoom.put(recordLast.getGaolao_win(), RoomName.gaolao);
            successCountRoom.put(recordLast.getHuaguo_win(), RoomName.huaguo);
            successCountRoom.put(recordLast.getShuilian_win(), RoomName.shuilian);
            successCountRoom.put(recordLast.getWuzhi_win(), RoomName.wuzhi);
            successCountRoom.put(recordLast.getLiusha_win(), RoomName.liusha);
            successCountRoom.put(recordLast.getBajiao_win(), RoomName.bajiao);
            successCountRoom.entrySet().stream()
                    .distinct()
                    .max(((o1, o2) -> o2.getKey() - o1.getKey()))
                    .ifPresent(entry -> newPredict.setPrediction_room(entry.getValue()));
            return;
        }
        Random random = new Random();
        int nextInt = random.nextInt(8) + 1;
        newPredict.setPrediction_room(RoomName.getRoomNameById.get(nextInt));
    }
}
